use anyhow::{Context, Result};
use chrono::Local;
use fern;
use log::{debug, error, info, warn};
use std::fs;
use std::path::Path;
use std::time::Duration;
use tokio;

// -------------------------- 配置常量 --------------------------
// 监控的目标文件路径
const MONITORED_FILE: &str = "C:\\ProgramData\\coconet\\snapshot.jpg";
// 目标文件存在时生成的输出文件
const OUTPUT_FILE: &str = "C:\\ProgramData\\coconet\\cv.txt";
// 定时检查间隔（秒），可按需调整
const CHECK_INTERVAL: u64 = 10;
// 日志文件夹名称（在程序运行目录下）
const LOG_DIR: &str = "logs";
// 日志级别（debug < info < warn < error）
const LOG_LEVEL: &str = "debug";
const FIXED_LOG_DIR: &str = "D:\\file_monitor_logs";

#[tokio::main]
async fn main() -> Result<()> {
    // 1. 初始化日志系统（文件+控制台双输出）
    init_fern_logger()?;

    // 2. 获取程序运行目录（用于日志存储路径展示）
    let exe_path = std::env::current_exe()
        .with_context(|| "无法获取程序路径")?;
    let exe_dir = exe_path.parent()
        .with_context(|| "无法获取程序运行目录")?;

    // 3. 输出程序启动信息
    info!("=== 文件监控程序已启动 ===");
    info!("程序运行目录: {}", exe_dir.display());
    info!("监控文件: {}", MONITORED_FILE);
    info!("输出文件: {}", OUTPUT_FILE);
    info!("检查间隔: {} 秒", CHECK_INTERVAL);
    info!("日志路径: {}/{}", exe_dir.display(), LOG_DIR);
    info!("停止程序: 按 Ctrl+C");

    // 4. 循环定时检查文件（核心逻辑）
    loop {
        match check_and_create_file() {
            Ok(_) => debug!("本次文件检查完成"),
            Err(e) => error!("文件检查失败: {}", e),
        }
        // 非阻塞睡眠（不占用CPU）
        tokio::time::sleep(Duration::from_secs(CHECK_INTERVAL)).await;
    }
}

// -------------------------- 日志初始化函数 --------------------------
/// 初始化fern日志：同时输出到「控制台」和「程序目录/logs/日期.log」
fn init_fern_logger() -> Result<()> {
    // 设置日志级别
    let log_level = match LOG_LEVEL.to_lowercase().as_str() {
        "trace" => log::LevelFilter::Trace,
        "debug" => log::LevelFilter::Debug,
        "info" => log::LevelFilter::Info,
        "warn" => log::LevelFilter::Warn,
        "error" => log::LevelFilter::Error,
        _ => {
            warn!("未知的日志级别: {}, 使用默认级别info", LOG_LEVEL);
            log::LevelFilter::Info
        }
    };

    // 创建日志文件夹
    let log_dir = Path::new(FIXED_LOG_DIR);
    if !log_dir.exists() {
        fs::create_dir_all(&log_dir)
            .with_context(|| format!("无法创建日志目录: {}", log_dir.display()))?;
        debug!("日志目录已创建: {}", log_dir.display());
    }

    // 日志文件命名（按日期）
    let today = Local::now().format("%Y-%m-%d").to_string();
    let log_file = log_dir.join(format!("{}.log", today));

    // 配置fern日志器
    fern::Dispatch::new()
        // 全局日志级别
        .level(log_level)
        // 输出到控制台
        .chain(
            fern::Dispatch::new()
                .format(move |out, message, record| {
                    out.finish(format_args!(
                        "[{}] [{}] {}",
                        chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f"),
                        record.level(),
                        message
                    ))
                })
                .chain(std::io::stdout()),
        )
        // 输出到文件
        .chain(
            fern::Dispatch::new()
                .format(move |out, message, record| {
                    out.finish(format_args!(
                        "[{}] [{}] {}",
                        chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f"),
                        record.level(),
                        message
                    ))
                })
                .chain(fern::log_file(log_file)?),
        )
        .apply()
        .with_context(|| "无法初始化日志系统")?;

    Ok(())
}

// -------------------------- 文件检查与创建函数 --------------------------
/// 核心逻辑：检查snapshot.jpg是否存在，存在则创建cv.txt（带错误处理）
fn check_and_create_file() -> Result<()> {
    let monitor_path = Path::new(MONITORED_FILE);
    let output_path = Path::new(OUTPUT_FILE);

    // 1. 检查监控文件是否存在
    if !monitor_path.exists() {
        debug!("监控文件不存在: {}", monitor_path.display());
        return Ok(());
    }
    info!("发现监控文件: {}", monitor_path.display());

    // 2. 避免重复创建cv.txt
    if output_path.exists() {
        warn!("输出文件已存在，跳过: {}", output_path.display());
        return Ok(());
    }

    // 3. 确保输出目录存在
    if let Some(parent_dir) = output_path.parent() {
        if !parent_dir.exists() {
            fs::create_dir_all(parent_dir)
                .with_context(|| format!("无法创建目录: {}", parent_dir.display()))?;
            info!("已创建目录: {}", parent_dir.display());
        }
    }

    // 4. 创建cv.txt并写入"ok"
    fs::write(output_path, "ok")
        .with_context(|| format!("无法创建文件: {}", output_path.display()))?;
    info!("成功创建文件: {}", output_path.display());

    Ok(())
}
    